
import { _decorator, Component, Node, Canvas, Prefab, instantiate, Asset, director, tween, Vec3 } from 'cc';
import { BundlesConst, FormConst } from '../../const/Const';
import { formModel } from '../../model/formModel';
import ToastForm from '../ui/toastForm';
import { UiForm } from '../ui/uiForm';
import { BaseObject } from './baseObject';
import { poolComponent } from './poolComponent';
import { poolManager } from './poolManager';
import { resourceUtil } from './resourceUtil';

const { ccclass, property } = _decorator;
@ccclass('uiManager')
export class uiManager {
    public static layerIndex: number = 1;
    public static get uiRoot(): Node {
        let scene = director.getScene();
        let canvas = scene.getChildByName('Canvas') as unknown as Node;
        return canvas;
    };
    public static uiRootPath: string = "";
    public static mToastForm: any = null;


    public static showToast(msg: string, isRich: boolean = false) {
        // moosnow.form.showToast(msg);
        if (this.mToastForm == null) {
            this.pushUIForm(FormConst.toastForm, (node) => {
                this.mToastForm = node.getComponent(ToastForm);
                node.setSiblingIndex(this.uiRoot.children.length - 1);
                if (this.mToastForm)
                    this.mToastForm.show(msg, isRich);
            });
        } else {
            this.mToastForm.node.setSiblingIndex(this.uiRoot.children.length - 1);
            this.mToastForm.show(msg, isRich);
        }
    }

    private static singleFormQueue: Array<formModel> = [];
    private static addFormQueue(formPathOrName: string, callback: (formOwner: Node) => void, bundleKey: string = BundlesConst.form) {
        if (this.singleFormQueue.find(item => item.formPathOrName == formPathOrName)) {
            return;
        }
        this.singleFormQueue.push(new formModel(formPathOrName, callback, bundleKey));
    }

    private static hasFormQueue(formName: string): boolean {
        return !!this.singleFormQueue.find(item => item.formName == formName);
    }

    private static removeFormQueue(formName: string) {
        this.singleFormQueue = this.singleFormQueue.filter(item => item.formName != formName);
    }

    /**
     * 显示一个ui
     * @param {string} formName  预设名字 
     * @param {Object} data 携带的自定义数据
     * @param {Function} callback ui显示后回调:(formOwner)
     * @param {string} nameOrUrl bundle名字或者url 对象池中不存在formName时，会加载bundle
     */
    public static pushUIForm(formPathOrName: string, callback?: (formOwner: Node) => void, bundleKey: string = BundlesConst.form) {

        let names = formPathOrName.split("/");
        let formName = names[names.length - 1];

        if (this.hasFormQueue(formName)) {
            return;
        }
        this.addFormQueue(formPathOrName, callback, bundleKey);

        let p = poolManager.getPrefab(formName);

        if (p == null) {
            resourceUtil.loadBundleRes<Prefab>(bundleKey, formPathOrName, (err, res) => {
                if (err) {
                    console.error(err);
                    return;
                }
                poolManager.addPrefab(res);
                this.loadFormPrefabCompleteCall(formPathOrName, callback);
            });
            return;
        }
        else {
            this.loadFormPrefabCompleteCall(formPathOrName, callback);
        }
    }

    private static loadFormPrefabCompleteCall(formPathOrName: string, callback?: (formOwner: Node) => void) {
        let names = formPathOrName.split("/");
        let formName = names[names.length - 1];
        let p = poolManager.getPrefab(formName);
        let formNode = poolManager.getNode(p, this.uiRoot);
        let pc = formNode.getComponent(poolComponent) || formNode.addComponent(poolComponent);
        pc.tag = formName;
        this.addFormTag(formNode, formName);
        formNode.active = true;
        if (callback) {
            callback(formNode);
        }
    }

    private static addFormTag(form: Node, formName: string): void {
        var script = form.getComponent(UiForm);
        if (script == null)
            script = form.addComponent(UiForm);
        form.active = true;
        script.formName = formName;
        script.showEffect();
        script.node.setSiblingIndex(script.node.parent.children.length - 1);
    }

    static getUIForm(formName: string): Node {
        let stackAll = poolManager.getStack(formName);
        if (stackAll && stackAll.length > 0)
            return stackAll[0];
        else
            return null;
    }

    static getUIForms(formName: string): Node[] {
        return poolManager.getStack(formName);
    }

    static hideUIForm(formName: string, cb?: () => void) {
        var formNode = this.getUIForm(formName);
        if (formNode)
            this.hideUIFormByNode(formNode, cb);
    }

    static hideAllUIForm(formName: string) {
        var nodeList = this.getUIForms(formName);
        if (nodeList)
            nodeList.forEach(item => {
                this.hideUIFormByNode(item);
            });
    }

    /**
     * 隐藏某个UI
     * @param {string} name 预设名
     * @param {fun} cb 携带的自定义数据
     */
    static hideUIFormByNode(formNode: Node, cb?: () => void) {
        var form = formNode.getComponent(UiForm);
        if (form) {
            if (form.isPopEffect) {
                let owner = formNode;
                // this.popCloseAnim(owner)
                //     .then(() => {
                //         formNode.active = false;
                //         // formNode.removeFromParent();
                //         poolManager.putNode(formNode);
                //         if (cb)
                //             cb();
                //     })
                form.closeEffect(() => {
                    formNode.active = false;
                    // formNode.removeFromParent();
                    poolManager.putNode(formNode);
                    if (cb)
                        cb();
                })
            }
            else {
                form.hideAnim(() => {
                    formNode.active = false;
                    // formNode.removeFromParent();
                    poolManager.putNode(formNode);
                    if (cb)
                        cb();
                })
            }
            this.removeFormQueue(form.formName);
        }
        else {
            formNode.active = false;
            this.removeFormQueue(formNode.name);
            poolManager.putNode(formNode);
        }

    }

    static destroyUIForm(form: Node) {
        poolManager.removeStack(form);
        form.active = false;
        form.removeFromParent();
        form.destroy();
    }

    static popOpenAnim(node: Node) {

        return new Promise(resolve => {
            node.scale = new Vec3(1, 1, 1);
            tween(node)
                .to(0.1, { scale: new Vec3(1.2, 1.2, 1.2) }, { easing: 'bounceInOut' })
                .to(0.1, { scale: new Vec3(1, 1, 1) }, { easing: 'bounceInOut' })
                .call(() => {
                    resolve(null);
                })
                .start();
        })
    }

    static popCloseAnim(node: Node) {
        return new Promise(resolve => {
            node.scale = new Vec3(1, 1, 1);
            tween(node)
                .to(0.1, { scale: new Vec3(0, 0, 0) }, { easing: 'bounceInOut' })
                .call(() => {
                    resolve(null);
                })
                .start();
        });
    }
}

/**
 * [1] Class member could be defined like this.
 * [2] Use `property` decorator if your want the member to be serializable.
 * [3] Your initialization goes here.
 * [4] Your update function goes here.
 *
 * Learn more about scripting: https://docs.cocos.com/creator/3.0/manual/en/scripting/
 * Learn more about CCClass: https://docs.cocos.com/creator/3.0/manual/en/scripting/ccclass.html
 * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.0/manual/en/scripting/life-cycle-callbacks.html
 */
